﻿using EssentialDialog;
using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AudioLabelerTool
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        Toaster.Toast Toast = null;
        private void Form1_Load(object sender, EventArgs e)
        {
            Toast = new Toaster.Toast(this, lblToastFontReference.Font);
            
        }

        private void 打开文件ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "Wave声音文件|*.wav";
            if(ofd.ShowDialog(this) == DialogResult.OK)
            {
                loadFile(ofd.FileName);
            }
        }

        AudioPlayer audioPlayer = null;

        string extraDataPath = ".tlbl";

        private void loadFile(String path)
        {
            workingTimer.Enabled = false;
            using(AudioFileReader afr = new AudioFileReader(path))
            {
                waveformRenderControl1.setWaveform(WaveformRenderControl.scanForWaveFile(afr));
            }
            audioPlayer?.Dispose();
            audioPlayer = new AudioPlayer(path);
            audioPath = path;
            if (File.Exists(path + extraDataPath))
            {
                dataClass = Newtonsoft.Json.JsonConvert.DeserializeObject<DataClass>(File.ReadAllText(path + extraDataPath));
            }
            else
            {
                dataClass = new DataClass();
                
            }
            loadData();
            waveformRenderControl1.CurrentDisplayPosition = dataClass.currentSecond;
            workingTimer.Enabled = true;
            
        }

        private void loadData()
        {
            tblData.Rows.Clear();
            tblData.SuspendLayout();
            foreach (var item in dataClass.labels)
            {
                tblData.Rows.Add(item.id, timeToStr(item.Begin), timeToStr(item.End), item.Transcription, "查看", "更新", "删除");
            }
            tblData.ResumeLayout();
        }

        private string audioPath = null;

        private void 保存文件ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if(audioPath != null)
            {
                File.WriteAllText(audioPath + extraDataPath, Newtonsoft.Json.JsonConvert.SerializeObject(dataClass,Newtonsoft.Json.Formatting.Indented));
                Toast.ShowMessage("保存成功");
            }
        }

        private float endPlayingTime = 0;

        private void workingTimer_Tick(object sender, EventArgs e)
        {
            if(audioPlayer == null)
            {
                workingTimer.Enabled = false;
                return;
            }
            dataClass.currentSecond = waveformRenderControl1.CurrentDisplayPosition;
            if(audioPlayer.IsPlaying)
            {

                waveformRenderControl1.SetPlayingPos(audioPlayer.Position);
                if(audioPlayer.Position >= endPlayingTime)
                {
                    audioPlayer.IsPlaying = false;
                }
                lblPlayingTime.Text = timeToStr(audioPlayer.Position);
            }
            else
            {
                waveformRenderControl1.SetPlayingPos(-1);
                lblPlayingTime.Text = timeToStr(-1);
            }
            if (waveformRenderControl1.HasSelection)
            {
                lblStartEnd.Text = $"{timeToStr(waveformRenderControl1.SelectionStart)}\r\n{timeToStr(waveformRenderControl1.SelectionEnd)}\r\n{timeToStr(waveformRenderControl1.SelectionEnd - waveformRenderControl1.SelectionStart)}";
            }
            else
            {
                lblStartEnd.Text = "--:--.---\r\n--:--.---\r\n--:--.---";
            }

            if (isAnimatingToPosition)
            {
                if(animateToPosition < 0)
                {
                    animateToPosition = 0;
                }
                if(animateToPosition > waveformRenderControl1.TotalDisplayRange - 0.5f) {
                    animateToPosition = waveformRenderControl1.TotalDisplayRange - 0.5f;
                }
                float delta = animateToPosition - waveformRenderControl1.CurrentDisplayPosition;
                delta *= 0.2f;
                waveformRenderControl1.CurrentDisplayPosition += delta;
                if(Math.Abs(delta) < 0.02)
                {
                    waveformRenderControl1.CurrentDisplayPosition = animateToPosition;
                    isAnimatingToPosition = false;
                }
            }
        }

        private string timeToStr(float fsecond)
        {
            if(fsecond < 0) { return "--:--.---"; }
            int second = (int)fsecond;
            int minute = second / 60;
            second = second % 60;
            string str = "";
            if (minute < 10) { str += "0"; }
            str += minute + ":";
            if (second < 10) { str += "0"; }
            str += second+".";
            int ms = (int)((fsecond % 1f) * 1000);

            if (ms < 100) { str += "0"; }
            if (ms < 10) { str += "0"; }
            return str + ms;
        }

        public DataClass dataClass = null;

        public class DataClass
        {
            public float currentSecond = 0f;
            public List<AudioLabel> labels = new List<AudioLabel>();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (audioPlayer == null)
            {
                return;
            }
            audioPlayer.IsPlaying = false;
        }

        private void btnPlay_Click(object sender, EventArgs e)
        {
            if(audioPlayer == null) { return; }
            if (audioPlayer.IsPlaying)
            {
                audioPlayer.Position += 0.56f;
            }
            else 
            if(waveformRenderControl1.HasSelection)
            {
                audioPlayer.Position = waveformRenderControl1.SelectionStart;
                endPlayingTime = waveformRenderControl1.SelectionEnd;
                audioPlayer.IsPlaying = true;
            }
        }


        private void waveformRenderControl1_SelectionClick(object sender, float e)
        {
            if (audioPlayer == null) { return; }
            audioPlayer.Position = e;
            endPlayingTime = waveformRenderControl1.SelectionEnd;
            audioPlayer.IsPlaying = true;
        }

        private void waveformRenderControl1_PreviewClick(object sender, float e)
        {
            if (audioPlayer == null) { return; }
            audioPlayer.Position = e;
            if(e >= waveformRenderControl1.SelectionStart && e <= waveformRenderControl1.SelectionEnd)
            {

                endPlayingTime = waveformRenderControl1.SelectionEnd;
            }
            else
            {

                endPlayingTime = e + 5;
            }
            audioPlayer.IsPlaying = true;
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            if (!waveformRenderControl1.HasSelection)
            {
                Toast.ShowMessage("未选择音频切片");
                return;
            }
            if(txtInput.Text.Length <= 1)
            {
                Toast.ShowMessage("请输入文本内容");
                return;
            }
            AudioLabel item = new AudioLabel();
            item.Begin = waveformRenderControl1.SelectionStart;
            item.End = waveformRenderControl1.SelectionEnd;
            item.Transcription = txtInput.Text;
            tblData.Rows.Insert(0,item.id, timeToStr(item.Begin), timeToStr(item.End), item.Transcription, "查看", "更新", "删除");
            dataClass.labels.Insert(0, item);
            txtInput.Text = "";
        }

        bool canOverride = false;
        string lastViewId = "";
        private void tblData_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            if(e.RowIndex < 0) { return; }
            string id = tblData[0, e.RowIndex].Value.ToString();
            if (e.ColumnIndex == 4) // 查看
            {
                if(txtInput.TextLength <= 1 || canOverride) {
                    AudioLabel item = dataClass.labels.Where(al => al.id == id).FirstOrDefault();
                    if(item != null) {
                        txtInput.Text = item.Transcription;
                        waveformRenderControl1.SetSelection(item.Begin, item.End);
                        if(item.End - item.Begin < waveformRenderControl1.DisplayWidthRange)
                        {

                            animateToPosition = item.Begin + (item.End - item.Begin) / 2 - waveformRenderControl1.DisplayWidthRange / 2;
                        }
                        else
                        {

                            animateToPosition = item.Begin - 2;
                        }
                        isAnimatingToPosition = true;
                        canOverride = true;
                        lastViewId = id;
                    }
                    else
                    {
                        Toast.ShowMessage("找不到项目");
                    }
                }
                else
                {
                    Toast.ShowMessage("正在编辑中，请清空文本框之后查看");
                }
            }
            if (e.ColumnIndex == 5) // 更新
            {
                if (!waveformRenderControl1.HasSelection)
                {
                    Toast.ShowMessage("未选择音频切片");
                    return;
                }
                if (txtInput.Text.Length <= 1)
                {
                    Toast.ShowMessage("请输入文本内容");
                    return;
                }
                AudioLabel item = dataClass.labels.Where(al => al.id == id).FirstOrDefault();
                if(item != null)
                {
                    if(lastViewId != item.id)
                    {
                        
                        return;
                    }
                    item.Begin = waveformRenderControl1.SelectionStart;
                    item.End = waveformRenderControl1.SelectionEnd;
                    item.Transcription = txtInput.Text;
                    tblData[1, e.RowIndex].Value = timeToStr(item.Begin);
                    tblData[2, e.RowIndex].Value = timeToStr(item.End);
                    tblData[3, e.RowIndex].Value = item.Transcription;
                    canOverride = true;
                }
                else
                {
                    Toast.ShowMessage("找不到项目");
                }
            }
            if (e.ColumnIndex == 6) // 删除
            {
                AudioLabel item = dataClass.labels.Where(al => al.id == id).FirstOrDefault();
                if (item != null)
                {
                    if(MessageBox.Show(this, "是否关闭？请注意保存项目。", "", MessageBoxButtons.YesNo) == DialogResult.Yes)
                    {
                        dataClass.labels.Remove(item);
                        tblData.Rows.RemoveAt(e.RowIndex);
                    }
                }
                else
                {
                    Toast.ShowMessage("找不到项目");
                }
            }
        }

        private float animateToPosition = 0;
        private bool isAnimatingToPosition = false;


        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = MessageBox.Show(this,"是否关闭？请注意保存项目。","",MessageBoxButtons.YesNo) != DialogResult.Yes;
        }

        private void txtInput_TextChanged(object sender, EventArgs e)
        {
            canOverride = false;
        }

        private void 导出切片与标注ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (audioPath == null)
            {
                Toast.ShowMessage("未打开项目");
                return;
            }
            if (MessageBox.Show(this, "是否导出项目？", "", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                Enabled = false;
                FrmLongLoading.RunWork(this, (ps) =>
                {
                    ps.SetMessage("正在准备...");
                    ps.SetIndetermine(true);
                    string outDir = audioPath+"_export";
                    if(!Directory.Exists(outDir))
                    {
                        Directory.CreateDirectory(outDir);
                    }
                    using(AudioFileReader afr = new AudioFileReader(audioPath))
                    {

                        for (int i = 0; i < dataClass.labels.Count; i++)
                        {
                            ps.SetMessage($"正在导出...({i + 1}/{dataClass.labels.Count})");
                            AudioLabel item = dataClass.labels[i];
                            String audiofilename = Path.Combine(outDir, item.id.Replace("-", "") + ".wav");
                            String textfilename = audiofilename+".txt";
                            File.WriteAllText(textfilename, item.Transcription);
                            afr.CurrentTime = TimeSpan.Zero;
                            ISampleProvider dataProvider = afr.Skip(TimeSpan.FromSeconds(item.Begin)).Take(TimeSpan.FromSeconds(item.End - item.Begin));
                            using(WaveFileWriter wfw = new WaveFileWriter(File.Create(audiofilename),afr.WaveFormat))
                            {
                                float[] data = new float[2048];
                                int len = 0;
                                while (true)
                                {
                                    len = dataProvider.Read(data, 0, data.Length);
                                    if (len <= 0) { break; }
                                    wfw.WriteSamples(data, 0, len);
                                }
                            }
                        }

                    }

                }, err =>
                {
                    if(err == null)
                    {
                        Toast.ShowMessage("导出完成");
                    }
                    else
                    {
                        MessageBox.Show(err.GetType().FullName + ": " + err.Message, "发生错误");
                    }

                    Enabled = true;
                });
            }
        }

        private void txtInput_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.UnicodeText, true))
            {
                e.Effect = DragDropEffects.Copy;
            }
        }

        private void txtInput_DragDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.Text, true))
            {
                txtInput.Text = e.Data.GetData(DataFormats.UnicodeText, true).ToString();
            }
        }

        private void btnPrefixToggle(object sender, EventArgs e)
        {
            string chr = ((Button)sender).Text;
            if (txtInput.Text.StartsWith(chr))
            {
                txtInput.Text = txtInput.Text.Substring(chr.Length);
            }
            else
            {
                txtInput.Text = chr + txtInput.Text;
            }
        }
    }
}
